#!/bin/python

__author__="mbaez"
__date__ ="$19/10/2010 01:40:19$"

import time
import os,random
from Tablero import *
from Ficha import *
from Move import *

'''
Falta copiar lo que tengo en papel
'''
class Minimax:
	MAX_LEVEL=3
	def __init__(self, minimax_function=0, max_level=3):
		self.nodos=0
		self.tiempo=0
		self.start=minimax_function
		Minimax.MAX_LEVEL=max_level
		
	def minimax(self, tablero):
		t1=time.clock()
		ret, ret2 = self.max_value(tablero,1)
		indice= self.get_random_move(ret2)
		old,move_result=ret[indice], ret2[indice]
		t2=time.clock()
		self.tiempo=t2-t1
		print "Minimax Nodos Expandidos: "+str(self.nodos)
		print "Tiempo total:", self.tiempo
		return old, move_result
	
	def minimax_alpha_beta(self, tablero):
		self.BETA = (1L<<700)-1L
		self.ALPHA = -self.BETA
		t1=time.clock()
		ret, ret2 = self.max_value_alphabeta(tablero,1)
		indice= self.get_random_move(ret2, ret)
		old,move_result=ret[indice], ret2[indice]
		t2=time.clock()
		self.tiempo=t2-t1
		print "\t\t\tPoda Nodos Expandidos: "+str(self.nodos)
		print "\t\t\tTiempo total:", self.tiempo
		return old, move_result
	
	def min_value(self, tablero, level):
		mejor_move=Move(-1,-1,1000)
		old_move=Move(-1,-1)
		tablero_copy=tablero.get_copia()
		old_move_anterior_buffer=Move(-1,-1)
		mejor_list=[]
		old_list=[]
		if(not tablero.fin_del_juego()and level<=Minimax.MAX_LEVEL):
			old_list.append(old_move)
			mejor_list.append(mejor_move)
			for i in range(Tablero.MAX_DIM):
				for j in range(Tablero.MAX_DIM):
					old_move_buffer=Move(i,j)
					if tablero_copy.es_duenho(old_move_buffer):
						move_validos=tablero_copy.get_lista_move_validos(old_move_buffer, old_move_anterior_buffer)
						for move_valido in move_validos:
							#si es que puede come todas las fichas posibles
							lista=tablero_copy.comer_fichas(old_move_buffer,1,Ficha.USUARIO)
							if(len(lista)-1==0):
								#prueb una posicion
								tablero_copy.mover_ficha(old_move_buffer, move_valido)
							#expande al otro nodo
							old_result_list,move_result_list=self.max_value(tablero_copy, level+1)
							
							indice= self.get_random_move(move_result_list)
							
							old,move_result=old_result_list[indice], move_result_list[indice]
							#Obtiene el puntaje obtenido 
							#move_valido.score=tablero_copy.evaluar_suma_peso() #+ move_result.score
							move_valido.score=move_result.score
							'''
							Selecciona mayor valor del move para la computadora
							Significa que en el peor de los casos el valor sera el del mejor_move.score
							Atender el signo, todavia me confunde
							'''
							if move_valido.score <= mejor_move.score:
								mejor_list=[]
								old_list=[]
								mejor_move=move_valido
								old_move=old_move_buffer
								
								old_list.append(old_move)
								mejor_list.append(mejor_move)
								
							elif move_valido.score == mejor_move.score:
								mejor_list.append(mejor_move)
								old_list.append(old_move)
								
							#pone la ficha en su posicion inicial
							tablero_copy=tablero.get_copia()
							self.nodos+=1
						old_move_anterior_buffer=Move(i,j)
		else:
			mejor_move.score=tablero.evaluar()
			old_list.append(old_move)
			mejor_list.append(mejor_move)
			self.nodos+=1
	
		return old_list, mejor_list #old_move,mejor_move
		
	def max_value(self, tablero, level):
		range_list=[7,6,5,4,3,2,1,0]
		mejor_move=Move(-1,-1,-1000)
		old_move=Move(-1,-1)
		old_move_anterior_buffer=Move(-1,-1)
		tablero_copy=tablero.get_copia()
		mejor_list=[]
		old_list=[]

		if(not tablero.fin_del_juego() and level<=Minimax.MAX_LEVEL):
			old_list.append(old_move)
			mejor_list.append(mejor_move)
			for i in range_list:
				for j in range_list:
					old_move_buffer=Move(i,j)
					#Genera los movimientos validos para la computadora
					if (tablero_copy.es_duenho(old_move_buffer, Ficha.COMPUTADORA)):
						move_validos=tablero_copy.get_lista_move_validos(old_move_buffer,old_move_anterior_buffer,-1,Ficha.COMPUTADORA)
						for move_valido in move_validos:
							#self.nodos=self.nodos+1
							#si es que puede come todas las fichas posibles
							lista=tablero_copy.comer_fichas(old_move_buffer)
							if(len(lista)-1==0):
								#prueba una posicion
								tablero_copy.mover_ficha(old_move_buffer, move_valido)
							#expande el siguiente nodo
							old_result_list, move_result_list=self.min_value(tablero_copy, level+1)
							indice= self.get_random_move(move_result_list)
							old,move_result=old_result_list[indice], move_result_list[indice]
							#evalua el movimiento actual
							#move_valido.score=tablero_copy.evaluar_suma_peso(-1) +move_result.score
							#se le suma el puntaje obtenido al realizar dicho movimiento
							move_valido.score=move_result.score
							'''
							Selecciona el move de menor riesgo para la computadora
							Atender el signo, todavia me confunde
							'''
							if move_valido.score >= mejor_move.score:
								mejor_list=[]
								old_list=[]
								mejor_move=move_valido
								old_move=old_move_buffer
								old_list.append(old_move)
								mejor_list.append(mejor_move)
							elif move_valido.score == mejor_move.score:
								old_list.append(old_move)
								mejor_list.append(mejor_move)
							#pone el tablero en su posicion inicial
							tablero_copy=tablero.get_copia()
							self.nodos+=1
					old_move_anterior_buffer=Move(i,j)
		else:
			mejor_move.score=tablero.evaluar(-1)
			self.nodos+=1
			old_list.append(old_move)
			mejor_list.append(mejor_move)
			
		return  old_list, mejor_list #old_move,mejor_move
		
	def get_random_move(self, lista, l=[]):
		#print "list ",len(lista),"list2:",len(l)
		random.seed(os.urandom(32));
		#un random al pedo
		indice= random.randint(0, len(lista)-1) 
		
		return indice



	def min_value_alphabeta(self, tablero, level):
		mejor_move=Move(-1,-1,1000)
		old_move=Move(-1,-1)
		old_move_anterior_buffer=Move(-1,-1)
		tablero_copy=tablero.get_copia()
		old_move_anterior_buffer=Move(-1,-1)
		mejor_list=[]
		old_list=[]
		if(not tablero.fin_del_juego()and level<=Minimax.MAX_LEVEL):
			old_list.append(old_move)
			mejor_list.append(mejor_move)
			for i in range(Tablero.MAX_DIM):
				for j in range(Tablero.MAX_DIM):
					old_move_buffer=Move(i,j)
					if tablero_copy.es_duenho(old_move_buffer):
						move_validos=tablero_copy.get_lista_move_validos(old_move_buffer,old_move_anterior_buffer)
						for move_valido in move_validos:
							#si es que puede come todas las fichas posibles
							lista=tablero_copy.comer_fichas(old_move_buffer,2,Ficha.USUARIO)
							#self.nodos=self.nodos+1
							if(len(lista)-1==0):
								#prueb una posicion
								tablero_copy.mover_ficha(old_move_buffer, move_valido)
							#expande al otro nodo
							old_result_list,move_result_list=self.max_value_alphabeta(tablero_copy, level+1)
							indice= self.get_random_move(move_result_list,old_result_list)
							old,move_result=old_result_list[indice], move_result_list[indice]
							#Obtiene el puntaje obtenido 
							#move_valido.score=tablero_copy.evaluar_suma_peso() #+ move_result.score
							move_valido.score=move_result.score#tablero_copy.evaluar()
							'''
							Selecciona mayor valor del move para la computadora
							Significa que en el peor de los casos el valor sera el del mejor_move.score
							Atender el signo, todavia me confunde
							'''
							if move_valido.score <= mejor_move.score:
								mejor_list=[]
								old_list=[]
								mejor_move=move_valido
								old_move=old_move_buffer
								old_list.append(old_move)
								mejor_list.append(mejor_move)
								#mejor_move.score=move_result.score
							elif move_valido.score == mejor_move.score:
								old_list.append(old_move)
								mejor_list.append(mejor_move)

							if mejor_move.score < self.BETA:
								self.BETA = mejor_move.score
							
							if self.BETA <= self.ALPHA: 
								return  old_list, mejor_list#old_move,mejor_move
							
							#pone la ficha en su posicion inicial
							tablero_copy=tablero.get_copia()
							self.nodos+=1
						old_move_anterior_buffer=Move(i,j)
		else:
			mejor_move.score=tablero.evaluar()
			old_list.append(old_move)
			mejor_list.append(mejor_move)
			self.nodos+=1
		return  old_list, mejor_list#old_move,mejor_move
		
	def max_value_alphabeta(self, tablero, level):
		range_list=[7,6,5,4,3,2,1,0]
		mejor_move=Move(-1,-1,-1000)
		old_move=Move(-1,-1)
		old_move_anterior_buffer=Move(-1,-1)
		tablero_copy=tablero.get_copia()
		mejor_list=[]
		old_list=[]
		if(not tablero.fin_del_juego() and level<=Minimax.MAX_LEVEL):
			old_list.append(old_move)
			mejor_list.append(mejor_move)
			for i in range_list:
				for j in range_list:
					old_move_buffer=Move(i,j)
					#Genera los movimientos validos para la computadora
					if (tablero_copy.es_duenho(old_move_buffer, Ficha.COMPUTADORA)):
						#move_validos=tablero_copy.get_lista_move_validos(old_move_buffer,-1,Ficha.COMPUTADORA)
						move_validos=tablero_copy.get_lista_move_validos(old_move_buffer,old_move_anterior_buffer,-1,Ficha.COMPUTADORA)
						for move_valido in move_validos:
							#si es que puede come todas las fichas posibles
							lista=tablero_copy.comer_fichas(old_move_buffer)
							#self.nodos=self.nodos+1
							if(len(lista)-1==0):
								#prueba una posicion
								tablero_copy.mover_ficha(old_move_buffer, move_valido)
							#expande el siguiente nodo
							old_result_list, move_result_list=self.min_value_alphabeta(tablero_copy, level+1)
							indice= self.get_random_move(move_result_list,old_result_list)
							old,move_result=old_result_list[indice], move_result_list[indice]
							#evalua el movimiento actual
							#move_valido.score=tablero_copy.evaluar_suma_peso(-1) +move_result.score
							move_valido.score=move_result.score
							'''
							Selecciona el move de menor riesgo para la computadora
							Atender el signo, todavia me confunde
							'''
							if move_valido.score >= mejor_move.score:
								#print "new"
								mejor_move=move_valido
								old_move=old_move_buffer
								old_list=[]
								mejor_list=[]
								old_list.append(old_move)
								mejor_list.append(mejor_move)
								#mejor_move.score=move_result.score
							elif move_valido.score == mejor_move.score:
								#print "eq"
								old_list.append(old_move)
								mejor_list.append(mejor_move)
							#pone el tablero en su posicion inicial
							tablero_copy=tablero.get_copia()
							self.nodos+=1
					old_move_anterior_buffer=Move(i,j)
		else:
			mejor_move.score=tablero.evaluar(-1)
			old_list.append(old_move)
			mejor_list.append(mejor_move)
			self.nodos+=1
			
		return  old_list, mejor_list#old_move,mejor_move
		
